// 类装饰器
/* function logClz(params:any) {
    console.log(params); //params 就是被装饰的类HttpClient
    params.prototype.url = 'xxx'
    params.prototype.run = function(){
        console.log('run...');
    }
}
@logClz
class HttpClient {
    constructor(){
    }
}
let http:any = new HttpClient();
http.run(); */
// 装饰器工厂
/* function logClz(params?:string) {
    console.log('params: ',params);
    return function (target:any) {
        console.log('target ', target); //target: class HttpClient
        target.prtotype.url = params;
    }
}

@logClz('hello')
class HttpClient {
    constructor() {
    }
}
let http:any = new HttpClient();
console.log(http.url); */
// 重载构造函数
/* function logClz(target:any) {
    return class extends target {
        url = 'change url'
        getData(){
            console.log('getData:', this.url);
        }
    }
}

@logClz
class HttpClient {
    public url:string | undefined;
    constructor(){
        this.url = 'init url';
    }
    getData(){
        console.log(this.url);
    }
}

var http = new HttpClient();
http.getData() */
/* function fn<T extends {new(...args:any[])}>(constructor:T):T {
    class Ps extends constructor {
        age:number = 20; //扩展一个类型number的属性age;
    }
    return Ps;
}

@fn
class Person {

}
let p:any = new Person(); //装饰器之后Person已经变成Ps */
// 属性装饰器
/*
    属性装饰器表达式会在运行时当作函数被调用，传入两个参数：
    1.对于静态成员来说是类的构造函数，对于实例成员来说是类的原型对象；
    2.成员的名字；
 */
/* function logProp(params:any) {
    return function (target:any, attr:any) {
        console.log(target);
        console.log(attr)
        target[attr] = params;
        target.api = 'xxxxx';
        target.run = function () {
            console.log('run .....')
        }
    }
}

class httpClient {
    @logProp('http://www.baidu.com')
    public url:string | undefined
    constructor() {
    }
    getData(){
        console.log(this.url)
    }
}

let http:any = new httpClient();
http.getData();
console.log(http.api)
http.run() */
// 方法装饰器
/*
1.方法装饰器被应用到方法的属性描述符上，可以用来监视、修改、替换方法的定义；
2.方法装饰器会在运行时传入3个参数：
    1.对于静态成员来说是类的构造函数，对于实例成员来说是类的原型对象；
    2.成员的名字；
    3.成员的属性描述符；
*/
/* function get(params:any) {
    console.log(params) //装饰器传入的参数:http...
    return function(target:any, methodName:any, desc:any) {
        console.log(target) // 原型对象
        console.log(methodName) //getData
        console.log(desc) //...
        //修改被装饰的方法
        // 1.保存原方法体
        let oldMethod = desc.value;
        // 2.重新定义方法体
        desc.value = function(...args:any[]) {
            // 3.把传入的方法转换成字符串
            let newArgs = args.map(item => String(item))
            // 4.执行原来的方法
            oldMethod.apply(this, newArgs)
        }

    }
}

class HttpClient {
    constructor() { }
    @get('http://baidu.com')
    getData(...args:any[]) {
        console.log('getData: ', args);
    }
}

var http = new HttpClient();
http.getData(1, 2, true); */
